Skip to content

fix(ollama): always respond to model refresh, surface errors, and use form-edited base URL#878

Open
navedmerchant wants to merge 3 commits into
mainfrom
ollama_fetch_fix
Open

fix(ollama): always respond to model refresh, surface errors, and use form-edited base URL#878
navedmerchant wants to merge 3 commits into
mainfrom
ollama_fetch_fix

Conversation

@navedmerchant

@navedmerchant navedmerchant commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Closes: #877

Description

This PR fixes the Ollama model refresh flow so the settings panel always gives the user feedback and uses the URL they're actually looking at. The key implementation details:

Extension handler (webviewMessageHandler.ts)

  • The requestOllamaModels case now prefers baseUrl / apiKey from the incoming message values (which reflect the user's unsaved form edits) over the saved extension state, falling back to state only when values are absent. This lets a user validate a URL before saving it.
  • The handler always posts an ollamaModels response back to the webview — even when no models are found — so the UI can transition out of the loading state instead of hanging forever.
  • On fetch failure, the error is now logged to the output channel via provider.log(...) and an empty ollamaModels response is posted with the error message included, so the webview can display it directly. The previous console.debug silent swallow is removed.

Webview (ApiOptions.tsx)

  • The requestOllamaModels message dispatched on provider switch now includes values: { baseUrl, apiKey } from the current apiConfiguration, matching the new handler contract.

Ollama settings component (Ollama.tsx)

  • Replaced the useEvent hook from react-use with a native window.addEventListener("message", ...) inside a useEffect (with proper cleanup), removing the react-use dependency from this component.
  • Added a refreshStatus state machine (idleloadingsuccess | error) and a refreshError state to hold the backend error message.
  • Added a dedicated Refresh Models button (using the shared Button component) that shows a spinner while loading, disables itself during refresh, and displays success / error status text below the button. The error text prefers the backend-provided message and falls back to a localized generic error string.
  • The message listener only transitions status when the component is in the loading state, so unsolicited ollamaModels messages (e.g. from mount refresh) don't clobber the status display.

Test Procedure

Unit tests — extension handler (src/core/webview/__tests__/webviewMessageHandler.spec.ts)

  • cd src && npx vitest run core/webview/__tests__/webviewMessageHandler.spec.ts
  • New cases verify: empty models response is posted when no models found; error response with message is posted and logged on fetch failure; baseUrl/apiKey from message values take precedence over saved state.

Unit tests — Ollama component (webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx)

  • cd webview-ui && npx vitest run src/components/settings/providers/__tests__/Ollama.spec.tsx
  • New describe("Ollama Component - refresh models") block verifies: idle button render, correct requestOllamaModels payload with values on click, loading/disabled state, success state on models arrival, error state on empty models, backend error message display, and no-op for unsolicited messages when not loading.

Manual testing

  1. Select the Ollama provider in settings with Ollama not running.
  2. Click "Refresh Models" — the button shows a spinner, then displays the error message (e.g. "Connection refused") in red.
  3. Start Ollama, click refresh again — the button shows a success status and the model picker populates.
  4. Edit the base URL field but click refresh before saving — the refresh now queries the newly typed URL, not the stale saved one.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to approved GitHub Issue [BUG] Ollama model refresh stuck in loading, silently fails on errors, and uses stale base URL #877.
  • Scope: My changes are focused on the linked issue (Ollama refresh UX).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and updated tests have been added covering the handler and component changes.
  • Documentation Impact: I have considered documentation updates (see below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Screenshots / Videos

N/A — the refresh button and status text use existing shared UI primitives (Button, codicon icons, VS Code CSS variables) with no new visual design.

Documentation Updates

  • No documentation updates are required. The refresh button is self-explanatory and uses existing localized strings (settings:providers.refreshModels.*).

Additional Notes

The react-use useEvent import was removed from Ollama.tsx in favor of a native useEffect-based listener. This is a minor cleanup that reduces the component's dependency surface and makes the listener lifecycle explicit. The corresponding test mock for react-use was also removed.

Get in Touch

navedmerchant (GitHub) / navedmerchant on Discord

Summary by CodeRabbit

  • New Features
    • Added an Ollama “Refresh models” button in provider settings with loading, success, and error feedback.
    • Refresh requests now send the current Ollama base URL and API key.
  • Bug Fixes
    • Model refresh now always returns an ollamaModels payload to the UI, including empty results and explicit error details.
    • Refresh fails during cache refresh or model retrieval now surface clear error messages.
  • Tests
    • Expanded test coverage for empty results, request failures, credential precedence, and ignoring unsolicited updates.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d362b4a7-dff4-440e-9aef-d3ecfdc9368c

📥 Commits

Reviewing files that changed from the base of the PR and between a8bf706 and 3d69805.

📒 Files selected for processing (5)
  • src/core/webview/__tests__/webviewMessageHandler.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • webview-ui/src/components/settings/ApiOptions.tsx
  • webview-ui/src/components/settings/providers/Ollama.tsx
  • webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/core/webview/webviewMessageHandler.ts
  • webview-ui/src/components/settings/providers/Ollama.tsx
  • src/core/webview/tests/webviewMessageHandler.spec.ts
  • webview-ui/src/components/settings/providers/tests/Ollama.spec.tsx

📝 Walkthrough

Walkthrough

The Ollama model refresh flow now uses unsaved credentials, always returns a model response, surfaces fetch errors, and provides dedicated refresh controls with loading, success, and error feedback.

Changes

Ollama model refresh

Layer / File(s) Summary
Backend refresh response contract
src/core/webview/webviewMessageHandler.ts, src/core/webview/__tests__/webviewMessageHandler.spec.ts
The handler prefers request-provided credentials, refreshes the cache, always posts fetched or empty model results, logs failures, and includes error text in failure responses.
Settings refresh flow
webview-ui/src/components/settings/ApiOptions.tsx, webview-ui/src/components/settings/providers/Ollama.tsx, webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx
The settings UI sends current credentials, adds refresh lifecycle state and controls, renders status feedback, and tests request payloads and response handling.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Ollama
  participant ApiOptions
  participant webviewMessageHandler
  participant OllamaProvider

  User->>Ollama: Click refresh
  Ollama->>ApiOptions: Read current baseUrl and apiKey
  ApiOptions->>webviewMessageHandler: requestOllamaModels with values
  webviewMessageHandler->>OllamaProvider: flushModels with request credentials
  OllamaProvider-->>webviewMessageHandler: cache refresh result
  webviewMessageHandler->>OllamaProvider: getModels with request credentials
  OllamaProvider-->>webviewMessageHandler: Models or rejection
  webviewMessageHandler-->>Ollama: ollamaModels with optional error
  Ollama-->>User: Render success or error status
Loading

Suggested labels: awaiting-review

Suggested reviewers: hannesrudolph, taltas

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the Ollama refresh behavior changes.
Description check ✅ Passed The PR description matches the template and includes the linked issue, implementation summary, test procedure, checklist, and screenshots/docs sections.
Linked Issues check ✅ Passed The changes address the issue's four requirements: always respond, surface errors, use edited baseUrl/apiKey, and add refresh/status UI.
Out of Scope Changes check ✅ Passed No unrelated changes are evident; the listener cleanup and tests directly support the Ollama refresh fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ollama_fetch_fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.92683% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/webview/webviewMessageHandler.ts 76.92% 0 Missing and 3 partials ⚠️
...ew-ui/src/components/settings/providers/Ollama.tsx 88.88% 0 Missing and 3 partials ⚠️
webview-ui/src/components/settings/ApiOptions.tsx 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx (1)

232-355: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Missing coverage for the "preserve models on refresh error" scenario.

Given the model-list-wipe issue flagged in Ollama.tsx (setting ollamaModels to {} on any error response), consider adding a test that: loads models successfully first, then triggers a refresh that fails, and asserts the previously loaded models remain in ollamaModels/the picker.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx`
around lines 232 - 355, Add coverage in the “Ollama Component - refresh models”
tests for preserving previously loaded models after a failed refresh: complete
one successful refresh, trigger another refresh, dispatch an error response, and
assert the existing model remains visible in the picker or otherwise unchanged.
Use the existing dispatchMessage helper and refresh-button flow, and verify the
error state is shown without clearing the prior model.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx`:
- Around line 74-80: Update the `vi.mock("`@src/components/ui`", ...)` setup in
`Ollama.spec.tsx` to preserve the real barrel exports via `vi.importActual()`
and override only `Button`; ensure `ModelPicker` and `ThinkingBudget` continue
receiving their actual UI dependencies while the test-specific button behavior
remains.

---

Nitpick comments:
In `@webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx`:
- Around line 232-355: Add coverage in the “Ollama Component - refresh models”
tests for preserving previously loaded models after a failed refresh: complete
one successful refresh, trigger another refresh, dispatch an error response, and
assert the existing model remains visible in the picker or otherwise unchanged.
Use the existing dispatchMessage helper and refresh-button flow, and verify the
error state is shown without clearing the prior model.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8c7ef33f-2b62-4f1b-a1ac-fee40638bb54

📥 Commits

Reviewing files that changed from the base of the PR and between 116b70e and eff47f7.

📒 Files selected for processing (5)
  • src/core/webview/__tests__/webviewMessageHandler.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • webview-ui/src/components/settings/ApiOptions.tsx
  • webview-ui/src/components/settings/providers/Ollama.tsx
  • webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx

Comment thread webview-ui/src/components/settings/providers/__tests__/Ollama.spec.tsx Outdated
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 11, 2026
@taltas

taltas commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@roomote Please review this PR

@roomote

roomote Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

I saw the mention, but I could not start work on this PR with the current Roomote GitHub setup.

Comment on lines +49 to +52
if (Object.keys(newModels).length > 0) {
setRefreshStatus("success")
} else {
setRefreshStatus("error")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When Ollama is running but no models are installed, the backend posts { ollamaModels: {} } with no error field — so message.error is undefined here and the component shows the generic error string. Is a healthy-but-empty Ollama server really the same as a fetch failure?

Suggested change
if (Object.keys(newModels).length > 0) {
setRefreshStatus("success")
} else {
setRefreshStatus("error")
} else if (message.error) {
setRefreshStatus("error")
setRefreshError(message.error)
} else {
// Ollama reachable but no models installed yet
setRefreshStatus("success")

return () => {
window.removeEventListener("message", handleMessage)
}
}, [refreshStatus])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The [refreshStatus] dep tears down and re-adds the listener on the idle→loading transition — which fires synchronously right before vscode.postMessage(...) at line 66. If Ollama responds very quickly, could the response arrive in the brief gap and be silently dropped, leaving the UI stuck in loading?

A useRef for refreshStatus with a stable [] dep would avoid the re-subscription.

type: "requestOllamaModels",
values: {
baseUrl: apiConfiguration?.ollamaBaseUrl,
apiKey: apiConfiguration?.ollamaApiKey,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ollamaApiKey is now forwarded in values, but it’s not in the useDebounce dep array (further down around the dep list). Should it be, so a key-only change also triggers a re-fetch?

// the loading state. Include the error message so the webview
// can display it directly in the settings panel.
const errorMsg = error instanceof Error ? error.message : String(error)
provider.log(`[requestOllamaModels] Failed to fetch models: ${errorMsg}`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the user has typed a new URL but not saved, this log won’t show which host was actually attempted. Worth including baseUrl?

Suggested change
provider.log(`[requestOllamaModels] Failed to fetch models: ${errorMsg}`)
provider.log(`[requestOllamaModels] Failed to fetch models from ${baseUrl}: ${errorMsg}`)

// Always post a response so the webview refresh status can
// transition out of "loading" — even when no models are found.
provider.postMessageToWebview({ type: "ollamaModels", ollamaModels: ollamaModels })
} catch (error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both flushModels and getModels can throw into this catch, but the log says "Failed to fetch models" in both cases. A cache-layer failure and a network failure would look identical in the output channel — worth distinguishing?

apiKey: "secret-key",
})

expect(mockClineProvider.postMessageToWebview).toHaveBeenCalledWith({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockGetModels is asserted with the right options, but mockFlushModels isn’t checked here. If flushModels used the stale saved-state URL while getModels used the form-edited one, this test would still pass. Worth adding:

expect(mockFlushModels).toHaveBeenCalledWith(
  { provider: "ollama", baseUrl: "https://ollama.example.com", apiKey: "secret-key" },
  true
)

@github-actions github-actions Bot added awaiting-author PR is waiting for the author to address requested changes and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 16, 2026
@github-actions github-actions Bot removed the awaiting-author PR is waiting for the author to address requested changes label Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Ollama model refresh stuck in loading, silently fails on errors, and uses stale base URL

3 participants